/**
 * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 */

package com.iwindplus.boot.web;

import cn.hutool.core.text.CharSequenceUtil;
import com.iwindplus.boot.web.domain.property.FilterProperty;
import com.iwindplus.boot.web.domain.property.HttpClientProperty;
import com.iwindplus.boot.web.interceptor.HttpClientInterceptor;
import com.iwindplus.boot.web.manager.http.HttpClientManager;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * HttpClient配置.
 *
 * @author zengdegui
 * @since 2023/08/31 20:32
 */
@Slf4j
@Configuration
@EnableConfigurationProperties({HttpClientProperty.class, FilterProperty.class})
@ConditionalOnProperty(prefix = "http.client", name = "enabled", havingValue = "true", matchIfMissing = true)
public class HttpClientConfiguration {

    @Resource
    private HttpClientProperty property;

    /**
     * 创建 CloseableHttpClient.
     *
     * @param httpClientInterceptor HttpClient拦截器
     * @return CloseableHttpClient
     */
    @Bean
    public CloseableHttpClient closeableHttpClient(HttpClientInterceptor httpClientInterceptor) {
        PoolingHttpClientConnectionManagerBuilder connectionManager = PoolingHttpClientConnectionManagerBuilder
            .create()
            .setMaxConnTotal(this.property.getMaxConnTotal())
            .setMaxConnPerRoute(this.property.getMaxConnPerRoute());
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectionKeepAlive(TimeValue.of(this.property.getConnectionKeepAlive()))
            .setConnectionRequestTimeout(Timeout.of(this.property.getConnectionRequestTimeout()))
            .setRedirectsEnabled(this.property.getRedirectsEnabled())
            .setMaxRedirects(this.property.getMaxRedirects())
            .setCircularRedirectsAllowed(Boolean.FALSE)
            .setResponseTimeout(Timeout.of(this.property.getResponseTimeout()))
            .setContentCompressionEnabled(Boolean.TRUE)
            .build();
        HttpClientBuilder httpClientBuilder = HttpClients.custom()
            .setDefaultRequestConfig(requestConfig)
            .setConnectionManager(connectionManager.build())
            .addRequestInterceptorFirst(httpClientInterceptor);
        if (Boolean.TRUE.equals(this.property.getEnableRetry())) {
            // 重试次数
            httpClientBuilder.setRetryStrategy(
                new DefaultHttpRequestRetryStrategy(this.property.getMaxAttempts(), TimeValue.of(this.property.getPeriod())));
        } else {
            httpClientBuilder.disableAutomaticRetries();
        }
        if (Boolean.TRUE.equals(this.property.getProxyEnable())) {
            HttpHost proxy = new HttpHost(this.property.getProxyHost(), this.property.getProxyPort());
            httpClientBuilder.setProxy(proxy);
            String proxyUsername = this.property.getProxyUsername();
            String proxyPassword = this.property.getProxyPassword();
            if (CharSequenceUtil.isNotBlank(proxyUsername) && CharSequenceUtil.isNotBlank(proxyPassword)) {
                AuthScope authscope = new AuthScope(proxy);
                Credentials credentials = new UsernamePasswordCredentials(proxyUsername, proxyPassword.toCharArray());
                BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                credentialsProvider.setCredentials(authscope, credentials);
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
        }
        final CloseableHttpClient httpClient = httpClientBuilder.build();
        log.info("CloseableHttpClient={}", httpClient);
        return httpClient;
    }

    /**
     * 创建 HttpClientInterceptor.
     *
     * @return HttpClientInterceptor
     */
    @Bean
    public HttpClientInterceptor httpClientInterceptor() {
        HttpClientInterceptor httpClientManager = new HttpClientInterceptor();
        log.info("HttpClientInterceptor={}", httpClientManager);
        return httpClientManager;
    }

    /**
     * 创建 HttpClientManager.
     *
     * @return HttpClientManager
     */
    @Primary
    @Bean
    @ConditionalOnBean(CloseableHttpClient.class)
    public HttpClientManager httpClientManager() {
        HttpClientManager httpClientManager = new HttpClientManager();
        log.info("HttpClientManager={}", httpClientManager);
        return httpClientManager;
    }
}
